﻿using System;
using System.Collections.Generic;
using System.Windows.Threading;
using Microsoft.Practices.Unity;
using RG.Common;
using RG.Common.WPF;

namespace RG.Common.WPF.Workplaces
{
    public interface IAlarmDispatcher
    {
        IAlarmService AlarmService { get; set; }
        event AlarmTickArgs OnAlarm;
        DispatcherTimer AlarmTimer { get; set; }
        /// <summary>
        /// Интервал на который заряжается таймер
        /// в основном для тестов, но может еще для чего полезного пригодиться
        /// </summary>
        int AlarmInterval { get; set; }
        /// <summary>
        /// надо помнить время срабатывания последнего таймера
        /// ибо проверку на вхождение интервала надо делать от 
        /// него чтобы ничего не тарялось
        /// </summary>
        DateTime LastAlarmTime { get; set; }
        int DefaultInterval { get; set; }
        void AlarmInit(int managerId);
        void AlarmRenew();
    }

    public class AlarmDispatcher : IAlarmDispatcher
    {
        public IAlarmService AlarmService { get; set; }

        [Dependency]
        public WorkplaceWorker Worker { get; set; }

        [Dependency]
        public IWorkplace Workplace { get; set; }

        public DispatcherTimer AlarmTimer { get; set; }
        
        public event AlarmTickArgs OnAlarm;
        
        public int AlarmInterval { get; set; }
        public int DefaultInterval { get; set; }
        
        public DateTime LastAlarmTime { get; set; }
        public List<AlarmObject> AlarmList { get; set; }

        private bool hasAlarms;
        private int ManagerId;
        internal static readonly log4net.ILog Log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        public AlarmDispatcher()
        {
            Log.Info("Инициализация диспетчера напоминалок ...");
#if Release
            DefaultInterval = 10;
#else
            DefaultInterval = 3;
#endif
        }

        public void AlarmInit(int managerId)
        {
            LastAlarmTime = DateTime.Now;
            ManagerId = managerId;
            AlarmInterval = DefaultInterval;
            AlarmTimer = new DispatcherTimer {Interval = new TimeSpan(0, AlarmInterval, 0), IsEnabled = false};
            AlarmTimer.Tick += DoAlarm;
            SetAlarm();
        }

        public void AlarmRenew()
        {
            SetAlarm();
        }

        private void DoAlarm(object state, EventArgs eventArgs)
        {
            if (OnAlarm != null && hasAlarms) OnAlarm(ManagerId);
            LastAlarmTime = DateTime.Now;
            //В любом случае запускаем следующую итерацию напоминалки
            SetAlarm();
        }

        private void SetAlarm()
        {
            //на всякий случай останавливаем таймер
            AlarmTimer.IsEnabled = false;
            Worker.Do(() => AlarmService.GetFirstAlarmTime(ManagerId),
                      obj =>
                          {
                              //обязательно вертаем в дефолт, на случай если изменен интервал на меньше чем 5 мин
                              AlarmInterval = DefaultInterval;
                              hasAlarms = false;
                              if (obj != null)
                              {
                                  Log.InfoFormat("Ближайшая запланированная напоминалка в {0}мин", obj.AlarmTime);
                                  var alarmDiff = (obj.AlarmTime - LastAlarmTime);
                                  hasAlarms = true;
                                  //разницу смотрим в секундах чтобы не потерять напоминалки до которых меньше минуты
                                  if (alarmDiff.TotalMinutes > 0 && alarmDiff.TotalMinutes < DefaultInterval)
                                  {
                                      AlarmInterval = (int)decimal.Round((decimal)alarmDiff.TotalMinutes);
                                      AlarmTimer.Interval = new TimeSpan(alarmDiff.Ticks);
                                  }
                                  else if (alarmDiff.TotalMinutes < 0)
                                      AlarmInterval = 1;
                                  Log.InfoFormat("Следующая напоминалка через {0}сек", alarmDiff.TotalSeconds);
                              }
                              else
                                  Log.Info("Ни одной активной напоминалки заряжаем таймер на стандартный интервал.");
                              AlarmTimer.Interval = new TimeSpan(0, AlarmInterval, 0);
                              AlarmTimer.IsEnabled = true;
                          });
        }
    }

    public delegate void AlarmTickArgs(int managerId);
}
